(function (W, $) {
    var 

    /**
    * Classe Controladora
    */
    Controller = function () {
        this.form = new Formulario('#jrForm');
        this.utils = new Utils();
        this.tabs = new Tabs();
        this.ajax = new Ajax();
        this.modal = new Modal();
        this.parser = new Parser();
        this.about = new About();
        this.cep = new CEP(this);

        $('.icone').tipsy({ live: true });
    },

    /**
    * Navegação por Tabs
    * 
    * @param {string} selector
    */
    Tabs = function (selector) {
        selector = selector || '.jrTabs';
        this.$tabs = $(selector);

        var 
        $tab,
        $tabAll,
        $tabParent,
        tabSelector,
        $tabContent,
        $tabContentAll,
        tabClick = function () {
            $tab = $(this);
            $tabParent = $tab.parent().parent(); // .jrTabs
            tabSelector = $tab.attr('data-content');
            $tabAll = $tabParent.find('> ul > li[data-content]');
            $tabContentAll = $tabParent.find('> div');
            $tabContent = $tabContentAll.filter('[data-content="' + tabSelector + '"]');

            $tabContentAll.hide();
            $tabContent.show();
            $tabAll.removeClass('ativo');
            $tab.addClass('ativo');
        };

        if (this.$tabs.length) {
            this.$tabs.delegate('li[data-content]', 'click', tabClick);
        }
    },

    /**
    * Classe de Utilidades
    */
    Utils = function () {
        this.data = new Data();

        /**
        * Limpa qualquer caractere que não seja número de uma string
        * @param {string} string
        */
        this.limparNumero = function (string) {
            return (string || '').replace(/[^\d]+/g, '');
        };

        /**
        * Retorna verdadeiro se string for um cep válido
        * @param cep String
        */
        this.isCep = function (cep) {
            return (cep + '').match(RGX_CEP);
        };

        this.isTelefone = function (telefone) {
            return (telefone + '').match(RGX_TEL);
        };

        this.isObject = function (data) {
            return 'object' === typeof data;
        };

        this.isArray = function (data) {
            return data instanceof Array;
        };
    },

    /**
    * Classe de Tratamento de Data
    */
    Data = function () {
        var 
        self = this,
        parser = new Parser(this);

        /**
        * Retorna data segmentada
        * 
        * @param {mixed} data
        * @return {object}
        */
        this.formatar = function () // Anonima
        {
            var 
            RGX_BR = /^\d{2}(\/|-)\d{2}(\/|-)\d{4}$/,
            RGX_TIME = /^\d{4}-\d{2}-\d{2}.*/,
            dia, mes;

            return function (data) {
                if (!(data instanceof Date)) {
                    if (data.match(RGX_BR)) {
                        data = data.replace(/-/g, '/');
                        data = data.split('/');
                        data = data[2] + '/' + data[1] + '/' + data[0];
                    }
                    else if (data.match(RGX_TIME)) {
                        data = data.replace(/-/g, '/').replace(/\s\s/g, 'T');
                        data = data.split('.')[0];
                    }

                    data = new Date(Date.parse(data));
                }

                dia = data.getDate(),
                mes = data.getMonth() + 1;
                mes = mes < 10 ? '0' + mes : mes;
                dia = dia < 10 ? '0' + dia : dia;

                return isNaN(dia) ? null : {
                    'd': dia,
                    'm': mes,
                    'y': data.getFullYear(),
                    'h': data.getHours(),
                    'min': data.getMinutes()
                };
            };
        } ();

        /**
        * Retorna data formatada com horario
        * 
        * @param {string} data
        * @return {string}
        */
        this.getDataHora = function (data) {
            return parser.parse(this.formatar(data), '%d/%m/%y %h:%min');
        };

        /**
        * Retorna data formatada sem horario
        * 
        * @param {string} data
        * @return {string}
        */
        this.getData = function (data) {
            return parser.parse(this.formatar(data), '%d/%m/%y');
        };

        /**
        * Retorna idade por uma data
        * de forma simples sem verificar meses, dias e etc..
        * 
        * @return {integer}
        */
        this.getYearsOld = function (data) {
            var 
            atual = self.formatar(new Date());
            data = self.formatar(data);

            return (data === null || data.y >= atual.y) ? 0 : atual.y - data.y;
        };

        /**
        * Faz validação de idade minima
        * 
        * @param {integer} minYear Idade minima
        * @return {object}
        */
        this.validateYearsOld = function (minYear, maxYear) {
            minYear = minYear || 0;
            maxYear = maxYear || 200;

            var 
            validate = function (valor) {
                var 
                years = self.getYearsOld(valor),
                isMin = years >= minYear,
                isMax = years <= maxYear;

                // Se nenhum valor de entrada for passado também será retornado true
                return (!valor || (isMin && isMax)) ? true : false;
            };

            return {
                'validate': validate,
                'message': 'Idade miníma permitida: ' + minYear
            };
        };
    },

    /**
    * Classe de Parseamento
    *
    * @param {object} parent
    * @param {string} delim Delimitador das variáveis
    */
    Parser = function (parent, delim) {
        delim = delim || '%';

        /**
        * Faz o parse de uma String
        *
        * @param {object} data Dados a serem usados no parse
        * @param {string} tmpl Conteúdo a ser parseada
        * @return {string} Conteúdo parseado
        */
        this.parse = function (data, tmpl) {
            tmpl = tmpl + '';

            if ('object' === typeof data) {
                for (var i in data) {
                    if (data.hasOwnProperty(i)) {
                        tmpl = tmpl.replace(new RegExp(delim + i + '\\b', 'g'), data[i]);
                    }
                }
            }

            return tmpl;
        };
    },

    /**
    * Classe que faz validações em formulários
    *
    * @param {string} selector Seletor do formulário
    */
    Formulario = function (selector) {
        var self = this;

        this.$form = $(selector || 'form');

        var 
        submitCallback = function (form) {
            form.submit();
        };

        this.onSubmit = function (callback) {
            submitCallback = callback;

            return self;
        };

        this.reset = function () {
            self.$form[0].reset();

            return self;
        };

        this.submit = function () {
            self.$form.submit();

            return self;
        };

        this.valid = function () {
            return self.$form.valid();
        }

        this.validar = function () {
            self.$form.validate({
                submitHandler: submitCallback
            });

            return self;
        };

        this.New = function (selector) {
            return new Formulario(selector);
        };

        //this.onSubmit(submitCallback);
    },

    /**
    * Classe Ajax
    * 
    * @requires amplify
    */
    Ajax = function () {
        this.define = function (nome, url, type, cache) {
            type = type || 'POST';
            url = url.match(/https?|www/) ? url : Path(url);
            cache = cache || false;

            amplify.request.define(nome, 'ajax', {
                url: url,
                dataType: 'json',
                type: type,
                cache: cache
            });
        };

        this.request = function (nome, dados, callback) {
            amplify.request(nome, dados, callback);
        };

        /**
        * Atalho para o Plugin AutoComplete
        * 
        * @param {string} selector
        * @param {string} url
        * @param {array} dataMap
        * @param {function} callback
        */
        this.autocomplete = function (selector, url, dataMap, callback) {
            var 
            getData = function (data, index) {
                return dataMap.isFunction ? dataMap(data, index) : data[dataMap[index]];
            },
            $element = $(selector);
            $element.autocomplete(Path(url), {
                delay: 10,
                max: 10,
                minChars: 1,
                dataType: 'json',
                parse: function (data) {
                    var 
                    parsed = [];
                    data = data.result;

                    for (var i = -1; ++i < data.length; ) {
                        parsed[parsed.length] = {
                            data: data[i],
                            value: getData(data[i], 0) + "",
                            result: getData(data[i], 1) + ""
                        };
                    }

                    return parsed;
                },
                formatItem: function (item) {
                    return getData(item, 1);
                }
            }).result(function (e, item) {
                callback.apply(item, [item]);
            });
        };

        this.define('cep', CEP_SERVICE, 'GET');
    },

    /**
    * Classe Modal
    * 
    * @requires qtip2
    */
    Modal = function () {
        var 
        self = this,
        $qtipElement = $(W),
        $alert = $('div.jrMenu > div.alert'),
        $alertMsg = $alert.find('span');

        this.show = function (conteudo, titulo, button) {
            titulo = titulo || 'Atenção';
            conteudo = 'string' === typeof conteudo ? '<p>' + conteudo + '</p>' : conteudo;
            button = 'boolean' === typeof button ? button : true;

            try {
                $qtipElement.qtip({
                    id: 'modal',
                    content: { text: $(conteudo), title: { text: titulo || 'Modal', button: button} },
                    position: { my: 'center', at: 'center', target: $qtipElement },
                    show: { event: false, solo: true, modal: true, ready: true },
                    hide: false,
                    style: 'ui-tooltip-light ui-tooltip-rounded'
                });
            }
            catch (e) {
                log('Modal.show - error: qtip defined?', e);
            }
        };

        this.alert = function (message) {
            self.alert.hide();

            if (message.length) {
                $alertMsg.text(message);
                $alert.fadeIn('fast').delay(2e3).fadeOut(2e3);
            }
        };

        this.alert.hide = function () {
            $alert.hide();
            $alertMsg.empty();
        };

        this.alert.auto = function () {
            if ($alertMsg.text().length) {
                self.alert($alertMsg.text());
            }
        };

        this.spinner = function (message) {
            self.show($('<div class="loader"></div>'), (message || 'aguarde'), false);
        };

        this.hide = function () {
            $qtipElement.qtip('hide');
        };

        this.alert.auto();
    },

    /**
    * Classe de de AutoComplete de CEP
    * Retorna uma função que pode ser disparada para iniciar o listener
    */
    CEP = function (self) {
        return function () {
            var 
            $cep = $('#cep'),
            $endereco = $('#endereco'),
            $numero = $('#numero'),
            $bairro = $('#bairro'),
            $cidade = $('#cidade'),
            $estado = $('#estado');

            $cep.keyup(function () {
                if (self.utils.isCep(this.value)) {
                    self.ajax.request('cep', { cep: this.value }, function (res) {
                        $endereco.val(res.endereco);
                        $bairro.val(res.bairro);
                        $cidade.val(res.cidade);
                        $estado.val(res.sigla_estado);
                        $numero.focus();
                    });
                }
            });
        };
    },

    /**
    * Classe Logger
    *
    * @requires An WebBrowser
    */
    Logger = function () {
        return function () {
            if ('console' in W && 'apply' in console.log) {
                console.log.apply(console, arguments);
            }
        };
    },

    /**
    * Retorna o path relativo da página
    *
    * @param {string} path
    */
    Path = function (path) {
        var l = location;
        path = path || '';

        return l.protocol + '//' + l.hostname + ':' + l.port + '/' + path;
    },

    About = function () {
        var 
        about = "AGPR%20Systems%20-%20Sistema%20de%20Locadora%20de%20V%EDdeo%20-%202011%0A%0ADesenvolvido%20por%3A%0A%20%20-%20Afonso%20Rezende%0A%20%20-%20Anderson%20Borges%0A%20%20-%20Gerson%20Pereira%0A%20%20-%20Pedro%20Junior%0A%20%20-%20Rodrigo%20Oliveira";

        $(document).keyup(function (event) {
            if (event.ctrlKey && event.altKey && event.keyCode) {
                alert(unescape(about));
            }
        });
    },

    /**
    * URL do serviço de consulta de CEP
    */
    CEP_SERVICE = 'ajax/cep',

    /**
    * Regexes de Validação
    */
    RGX_CEP = /^\d{5}-\d{3}|\d{8}$/,
    RGX_TEL = /^([()\s-\d]){14}$/;

    $(function () {
        W.Path = Path;
        W.log = new Logger();
        W.con = new Controller();
    });
}
(window, jQuery));